using System;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using Raven.Client;
using Raven.Client.Document;

#if NET_40_OR_GREATER
    using Raven.Imports.Newtonsoft.Json.Serialization;
using Raven.Client.Embedded;
#else
    using Newtonsoft.Json.Serialization;
#endif

using Raven.Client.Indexes;

namespace OpenWaves.ActivityFeed.RavenDB
{
    public class DocumentStoreFactory : IDocumentStoreFactory
    {
        private readonly IDocumentStoreFactoryConfiguration configuration;

        public DocumentStoreFactory() : this(ServiceLocator.Resolve<IDocumentStoreFactoryConfiguration>())
        {
        }

        public DocumentStoreFactory(IDocumentStoreFactoryConfiguration configuration)
        {
            Contract.Requires<ArgumentNullException>(configuration != null);
            this.configuration = configuration;
        }

        [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
        public IDocumentStore CreateInitializedDocumentStore()
        {
            var documentStore = CreateDocumentStoreFromConfiguration(this.configuration);

            InitializeDocumentStore(documentStore);

            return documentStore;
        }

        public static void InitializeDocumentStore(IDocumentStore documentStore)
        {
            documentStore.Conventions.DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites;
            // Default RavenDB contract resolver ignores private fields, even when annotated with JsonProperty.
            documentStore.Conventions.JsonContractResolver = new DefaultContractResolver(true);
            documentStore.Conventions.IdentityPartsSeparator = "-";
            documentStore.Initialize();

            IndexCreation.CreateIndexes(typeof (ActivityFeedService).Assembly, documentStore);
        }

        [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
        private static DocumentStore CreateDocumentStoreFromConfiguration(IDocumentStoreFactoryConfiguration config)
        {
            switch (config.CreationMethod)
            {
#if NET_40_OR_GREATER
                case DocumentStoreCreationMethod.InMemory:
                    return new EmbeddableDocumentStore {RunInMemory = true};
                case DocumentStoreCreationMethod.Embedded:
                    return new EmbeddableDocumentStore {DataDirectory = config.DataDirectory};
#endif
                case DocumentStoreCreationMethod.Remote:
                    var documentStore = new DocumentStore();
                    documentStore.ParseConnectionString(config.ConnectionString);
                    return documentStore;
                default:
                    throw new InvalidOperationException(ExceptionMessage.Format("Unexpected value of {0}.CreationMethod: {1}", typeof(IDocumentStoreFactoryConfiguration).Name, config.CreationMethod));
            }
        }
    }
}